package crawler.model;

import business.service.MongoDbFactory;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import crawler.common.CategoryData;
import crawler.common.SourceData;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.log4j.Logger;
import org.bson.types.ObjectId;

public class SourceModel {

    private static final String POST_COLLECTION = "source";
    private static final Logger logger = Logger.getLogger(SourceModel.class);
    private static final Lock createLock_ = new ReentrantLock();
    private static SourceModel _instance = null;

    public static SourceModel getInstance() {
        if (_instance == null) {
            createLock_.lock();
            try {
                if (_instance == null) {
                    _instance = new SourceModel();

                }
            } finally {
                createLock_.unlock();
            }
        }
        return _instance;
    }

    public SourceModel() {
        try {
        } catch (Exception ex) {
            logger.error("PostModel: " + ex);
        }
    }

    public List<SourceData> getList(int start, int limit) {
        List<SourceData> lstPost = new LinkedList<>();
        try {
            BasicDBObject basicDBObject = new BasicDBObject("createdAt", -1);
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(POST_COLLECTION);
            DBCursor cursor = coll.find().sort(basicDBObject);

            if (limit != -1) {
                cursor = cursor.skip(start).limit(limit);
            }

            while (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                lstPost.add(fromDB(dbObject));
            }
        } catch (Exception ex) {
            logger.error("PostModel.getPost: " + ex.getMessage(), ex);
        }
        return lstPost;
    }
    public List<SourceData> getListByCategoryCode(String categoryCode, int start, int limit) {
        List<SourceData> lstPost = new LinkedList<>();
        try {
            BasicDBObject basicDBObject1 = new BasicDBObject("categoryCode", categoryCode);
            BasicDBObject basicDBObject2 = new BasicDBObject("createdAt", -1);
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(POST_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject1).sort(basicDBObject2);

            if (limit != -1) {
                cursor = cursor.skip(start).limit(limit);
            }

            while (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                lstPost.add(fromDB(dbObject));
            }
        } catch (Exception ex) {
            logger.error("PostModel.getPost: " + ex.getMessage(), ex);
        }
        return lstPost;
    }
    public SourceData getById(String id) {
        try {
            BasicDBObject basicDBObject = new BasicDBObject("_id", new ObjectId(id));
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(POST_COLLECTION);
            DBCursor cursor = coll.find(basicDBObject);
            if (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                SourceData postData = fromDB(dbObject);
                return postData;
            }
        } catch (Exception ex) {
            logger.error("SourceModel.getPostById: " + ex.getMessage(), ex);
        }
        return null;
    }

    public static SourceData fromDB(DBObject dbObject) {
        String objectId = ((ObjectId) dbObject.get("_id")).toString();
        String code = (String) dbObject.get("categoryCode");
        String name = (String) dbObject.get("url");
        String domain = (String) dbObject.get("domain");
        long createdAt = (long) dbObject.get("createdAt");
        SourceData postData = new SourceData(objectId, code, name, domain, createdAt);
        return postData;
    }

    public long getPostCount(String pid) {
        long count = 0;
        try {
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(POST_COLLECTION);
            count = coll.getCount();
        } catch (Exception ex) {
            logger.error("PostModel.getPostCount: " + ex.getMessage(), ex);
        }
        return count;
    }

    public boolean delete(String id) {
        try {
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(POST_COLLECTION);
            coll.remove(new BasicDBObject("_id", new ObjectId(id)));

            return true;
        } catch (Exception ex) {
            logger.error("SourceModel.delete: " + ex.getMessage(), ex);
        }
        return false;
    }

    public String add(SourceData data) {
        String id = "";
        DB db = null;
        DBCollection coll;
        try {
            BasicDBObject basicDBObject = generateObject(data);

            db = MongoDbFactory.getConnection();
            coll = db.getCollection(POST_COLLECTION);
            coll.insert(basicDBObject);

            ObjectId objectId = (ObjectId) basicDBObject.get("_id");
            id = objectId.toString();
        } catch (Exception ex) {
            logger.error("SourceModel.add: " + ex.getMessage(), ex);
        }
        return id;
    }

    public boolean update(SourceData postData) {
        try {
            BasicDBObject basicDBObject = generateObject(postData);

            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(POST_COLLECTION);

            BasicDBObject updateDBObject = new BasicDBObject("$set", basicDBObject);
            BasicDBObject searchDBQuery = new BasicDBObject("_id", new ObjectId(postData.getId()));
            coll.update(searchDBQuery, updateDBObject);
            return true;
        } catch (Exception ex) {
            logger.error("PostModel.updatePost: " + ex.getMessage());
        }
        return false;
    }

    public boolean checkPostExists(String link) {
        try {
            DB db = MongoDbFactory.getConnection();
            DBCollection coll = db.getCollection(POST_COLLECTION);
            BasicDBObject queryDBObject = new BasicDBObject("url", link);
            DBCursor cursor = coll.find(queryDBObject);

            if (cursor.hasNext()) {
                return true;
            }
        } catch (Exception ex) {
            logger.error("PostModel.checkPostExists: " + ex.getMessage(), ex);
        }
        return false;
    }

    private BasicDBObject generateObject(SourceData data) {
        BasicDBObject basicDBObject = new BasicDBObject()
                .append("categoryCode", data.getCategoryCode())
                .append("url", data.getUrl())
                .append("domain", data.getDomain())
                .append("createdAt", data.getCreatedAt());
        return basicDBObject;
    }
}
